Programmable integrated circuits (ICs) are often used to implement digital logic operations according to user configurable input. Example programmable ICs include complex programmable logic devices (CPLDs) and field programmable gate arrays (FPGAs). CPLDs often include several function blocks that are based on a programmable logic array (PLA) architecture with sum-of-products logic. A configurable interconnect matrix transmits signals between the function blocks.
An example FPGA includes an array of configurable logic blocks (CLBs) and a ring or columns of programmable input/output blocks (IOBs). The CLBs and IOBs are interconnected by a programmable interconnect structure (routing resources). The CLBs, IOBs, and interconnect structure are typically programmed by loading configuration data (“configuration bitstream”) into internal configuration memory cells. The state of the configuration memory cells determines the function of the CLBs, IOBs, and interconnect structure. The configuration bitstream may be read from an external memory, such as an EEPROM, EPROM, PROM and the like, though other types of memory may be used.
A typical design process begins with the creation of a circuit design. The circuit design specifies the function of a circuit at a schematic or logic level and may be represented using various hardware description languages (e.g., VHDL, ABEL, or Verilog) or schematic capture programs. The design is synthesized to produce a logical network list (“netlist”), and the synthesized design is mapped onto primitive components within the target device (e.g., programmable logic blocks of an FPGA).
Following mapping, placement of the components of the synthesized and mapped design is performed for the target device. During placement, each mapped component of the design is assigned to a physical position on the device. The placer attempts to place connected design objects in close physical proximity to one another in order to conserve space and increase the probability that the required interconnections between components will be successfully completed by the router. Placing connected components close to one another also generally improves the performance of the circuit since long interconnect paths are associated with excess capacitance and resistance, resulting in longer delays and greater power consumption.
To expedite development, respective teams of developers may develop different sub-circuits of a circuit design in parallel. However, such development must be properly coordinated between the teams so that all of the sub-circuits are placed and routed to meet various requirements of the respective sub-circuits such as timing requirements, resource requirements, etc. The timing and resource requirements of a circuit are specified as design constraints in a design constraints language. The circuits are placed and routed using the design constraints to ensure that requirements specified by the design constraints are satisfied in the placed and routed design.
There are two general implementation methodologies for parallel development: top-down and bottom-up. In the top-down approach, design tools implement a top-level circuit design first while treating modules as black-box instantiations. Respective development teams may then implement each module separately. A design may have a number of levels of hierarchy, where each module instantiation may contain sub-module instantiations. Typically, design floor planning is performed on a top-level design to allocate physical resources and timing budgets for each sub-module instantiation. This step is critical in dividing the overall design requirements and distributing them among the set of module instantiations. As each sub-module is implemented independent from the parent module (or context logic), it is imperative that the design constraints are applied to the module from the instantiation of the module. These design constraints serve as a specification for the sub-module of the parent module (or context logic) and thus become a requirement as to how the sub-module is to be implemented relative to its parent. The design constraints specified on an instantiation of a module are manipulated and applied to the module. For ease of reference, an instantiation of a module in a circuit design may be referred to as either a module instantiation or a module instance, and such terms are used interchangeably herein. For ease of reference, application of design constraints of a module instantiation to the module may be referred to as instance-to-module constraint propagation.
In the bottom-up approach, the tools implement the leaf sub-modules in the hierarchy first. The design tools incorporate the implemented sub-modules with parent logic in the next higher level and implement the sub-modules and parent logic together. This bottom-up process continues to implement each next-higher level of hierarchy until the entire circuit design is successfully implemented. As each module is implemented, design constraints are applied to control resource usage and to achieve target frequency requirements for the specific module. When the module is instantiated into its parent logic, the module's previous implementation may or may not apply depending on the overall objective. In one case, the module is reused as a hard core (e.g. module with implementation). In another case, the module is treated as a soft core (e.g., module without implementation). In the latter case, as the module instance is implemented together with its parent logic, it is imperative to apply the previously defined design constraints of the module to ensure the same requirements continue to be met. Similarly, the constraints specified for a module implementation are applied to the module instance while it is implemented together with its parent. For ease of reference, application of design constraints of a module to an instantiation of the module may be referred to as module-to-instance constraint propagation.